/*
 * Copyright (c) 2019, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 */

#include "level.h"

#define UNDEFINED_LEVEL                                                                    \
    {                                                                                      \
        .level = SEQ_LEVEL_MAX, .max_picture_size = 0, .max_h_size = 0, .max_v_size = 0,   \
        .max_display_rate = 0, .max_decode_rate = 0, .max_header_rate = 0, .main_mbps = 0, \
        .high_mbps = 0, .main_cr = 0, .high_cr = 0, .max_tiles = 0, .max_tile_cols = 0     \
    }

static const AV1LevelSpec av1_level_defs[SEQ_LEVELS] = {
    {.level            = SEQ_LEVEL_2_0,
     .max_picture_size = 147456,
     .max_h_size       = 2048,
     .max_v_size       = 1152,
     .max_display_rate = 4423680L,
     .max_decode_rate  = 5529600L,
     .max_header_rate  = 150,
     .main_mbps        = 1.5,
     .high_mbps        = 0,
     .main_cr          = 2.0,
     .high_cr          = 0,
     .max_tiles        = 8,
     .max_tile_cols    = 4},
    {.level            = SEQ_LEVEL_2_1,
     .max_picture_size = 278784,
     .max_h_size       = 2816,
     .max_v_size       = 1584,
     .max_display_rate = 8363520L,
     .max_decode_rate  = 10454400L,
     .max_header_rate  = 150,
     .main_mbps        = 3.0,
     .high_mbps        = 0,
     .main_cr          = 2.0,
     .high_cr          = 0,
     .max_tiles        = 8,
     .max_tile_cols    = 4},
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
    {.level            = SEQ_LEVEL_3_0,
     .max_picture_size = 665856,
     .max_h_size       = 4352,
     .max_v_size       = 2448,
     .max_display_rate = 19975680L,
     .max_decode_rate  = 24969600L,
     .max_header_rate  = 150,
     .main_mbps        = 6.0,
     .high_mbps        = 0,
     .main_cr          = 2.0,
     .high_cr          = 0,
     .max_tiles        = 16,
     .max_tile_cols    = 6},
    {.level            = SEQ_LEVEL_3_1,
     .max_picture_size = 1065024,
     .max_h_size       = 5504,
     .max_v_size       = 3096,
     .max_display_rate = 31950720L,
     .max_decode_rate  = 39938400L,
     .max_header_rate  = 150,
     .main_mbps        = 10.0,
     .high_mbps        = 0,
     .main_cr          = 2.0,
     .high_cr          = 0,
     .max_tiles        = 16,
     .max_tile_cols    = 6},
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
    {.level            = SEQ_LEVEL_4_0,
     .max_picture_size = 2359296,
     .max_h_size       = 6144,
     .max_v_size       = 3456,
     .max_display_rate = 70778880L,
     .max_decode_rate  = 77856768L,
     .max_header_rate  = 300,
     .main_mbps        = 12.0,
     .high_mbps        = 30.0,
     .main_cr          = 4.0,
     .high_cr          = 4.0,
     .max_tiles        = 32,
     .max_tile_cols    = 8},
    {.level            = SEQ_LEVEL_4_1,
     .max_picture_size = 2359296,
     .max_h_size       = 6144,
     .max_v_size       = 3456,
     .max_display_rate = 141557760L,
     .max_decode_rate  = 155713536L,
     .max_header_rate  = 300,
     .main_mbps        = 20.0,
     .high_mbps        = 50.0,
     .main_cr          = 4.0,
     .high_cr          = 4.0,
     .max_tiles        = 32,
     .max_tile_cols    = 8},
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
    {.level            = SEQ_LEVEL_5_0,
     .max_picture_size = 8912896,
     .max_h_size       = 8192,
     .max_v_size       = 4352,
     .max_display_rate = 267386880L,
     .max_decode_rate  = 273715200L,
     .max_header_rate  = 300,
     .main_mbps        = 30.0,
     .high_mbps        = 100.0,
     .main_cr          = 6.0,
     .high_cr          = 4.0,
     .max_tiles        = 64,
     .max_tile_cols    = 8},
    {.level            = SEQ_LEVEL_5_1,
     .max_picture_size = 8912896,
     .max_h_size       = 8192,
     .max_v_size       = 4352,
     .max_display_rate = 534773760L,
     .max_decode_rate  = 547430400L,
     .max_header_rate  = 300,
     .main_mbps        = 40.0,
     .high_mbps        = 160.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 64,
     .max_tile_cols    = 8},
    {.level            = SEQ_LEVEL_5_2,
     .max_picture_size = 8912896,
     .max_h_size       = 8192,
     .max_v_size       = 4352,
     .max_display_rate = 1069547520L,
     .max_decode_rate  = 1094860800L,
     .max_header_rate  = 300,
     .main_mbps        = 60.0,
     .high_mbps        = 240.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 64,
     .max_tile_cols    = 8},
    {.level            = SEQ_LEVEL_5_3,
     .max_picture_size = 8912896,
     .max_h_size       = 8192,
     .max_v_size       = 4352,
     .max_display_rate = 1069547520L,
     .max_decode_rate  = 1176502272L,
     .max_header_rate  = 300,
     .main_mbps        = 60.0,
     .high_mbps        = 240.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 64,
     .max_tile_cols    = 8},
    {.level            = SEQ_LEVEL_6_0,
     .max_picture_size = 35651584,
     .max_h_size       = 16384,
     .max_v_size       = 8704,
     .max_display_rate = 1069547520L,
     .max_decode_rate  = 1176502272L,
     .max_header_rate  = 300,
     .main_mbps        = 60.0,
     .high_mbps        = 240.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 128,
     .max_tile_cols    = 16},
    {.level            = SEQ_LEVEL_6_1,
     .max_picture_size = 35651584,
     .max_h_size       = 16384,
     .max_v_size       = 8704,
     .max_display_rate = 2139095040L,
     .max_decode_rate  = 2189721600L,
     .max_header_rate  = 300,
     .main_mbps        = 100.0,
     .high_mbps        = 480.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 128,
     .max_tile_cols    = 16},
    {.level            = SEQ_LEVEL_6_2,
     .max_picture_size = 35651584,
     .max_h_size       = 16384,
     .max_v_size       = 8704,
     .max_display_rate = 4278190080L,
     .max_decode_rate  = 4379443200L,
     .max_header_rate  = 300,
     .main_mbps        = 160.0,
     .high_mbps        = 800.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 128,
     .max_tile_cols    = 16},
    {.level            = SEQ_LEVEL_6_3,
     .max_picture_size = 35651584,
     .max_h_size       = 16384,
     .max_v_size       = 8704,
     .max_display_rate = 4278190080L,
     .max_decode_rate  = 4706009088L,
     .max_header_rate  = 300,
     .main_mbps        = 160.0,
     .high_mbps        = 800.0,
     .main_cr          = 8.0,
     .high_cr          = 4.0,
     .max_tiles        = 128,
     .max_tile_cols    = 16},
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
    UNDEFINED_LEVEL,
};

typedef enum {
    LUMA_PIC_SIZE_TOO_LARGE,
    LUMA_PIC_H_SIZE_TOO_LARGE,
    LUMA_PIC_V_SIZE_TOO_LARGE,
    LUMA_PIC_H_SIZE_TOO_SMALL,
    LUMA_PIC_V_SIZE_TOO_SMALL,
    TOO_MANY_TILE_COLUMNS,
    TOO_MANY_TILES,
    TILE_RATE_TOO_HIGH,
    TILE_TOO_LARGE,
    SUPERRES_TILE_WIDTH_TOO_LARGE,
    CROPPED_TILE_WIDTH_TOO_SMALL,
    CROPPED_TILE_HEIGHT_TOO_SMALL,
    TILE_WIDTH_INVALID,
    FRAME_HEADER_RATE_TOO_HIGH,
    DISPLAY_RATE_TOO_HIGH,
    DECODE_RATE_TOO_HIGH,
    CR_TOO_SMALL,
    TILE_SIZE_HEADER_RATE_TOO_HIGH,
    BITRATE_TOO_HIGH,
    DECODER_MODEL_FAIL,

    TARGET_LEVEL_FAIL_IDS,
    TARGET_LEVEL_OK,
} TARGET_LEVEL_FAIL_ID;

static double get_max_bitrate(const AV1LevelSpec *const level_spec, int tier,
                              BITSTREAM_PROFILE profile) {
    if (level_spec->level < SEQ_LEVEL_4_0)
        tier = 0;
    const double bitrate_basis = (tier ? level_spec->high_mbps : level_spec->main_mbps) * 1e6;
    const double bitrate_profile_factor = profile == PROFILE_0 ? 1.0
                                                               : (profile == PROFILE_1 ? 2.0 : 3.0);
    return bitrate_basis * bitrate_profile_factor;
}

double svt_av1_get_max_bitrate_for_level(AV1_LEVEL level_index, int tier,
                                         BITSTREAM_PROFILE profile) {
    assert(is_valid_seq_level_idx((uint8_t)level_index));
    return get_max_bitrate(&av1_level_defs[level_index], tier, profile);
}
